from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
from carts.serializers import CartSerializers, CartsSerializers, CartDeleteSerializers, CartSelectionSerializers
from django_redis import get_redis_connection
import pickle, base64

from goods.models import SKU


class CartView(APIView):

    def perform_authentication(self, request):
        # 进入视图函数后调用试图方法先不进行用户验证
        pass

    # 增加购物车数据
    def post(self, request):
        # 1获取前端数据
        data = request.data
        # 2验证数据
        ser = CartSerializers(data=data)
        ser.is_valid()
        # 3获取验证后的数据
        sku_id = ser.validated_data['sku_id']
        count = ser.validated_data['count']
        selected = ser.validated_data['selected']

        # 判断用户登录状态
        try:
            user = request.user
        except:
            user = None

        if user:
            # 用户已登录 redis
            # 建立redis连接
            conn = get_redis_connection('cart')
            #　写入hash数据 sku_id count
            conn.hincrby('cart_%s' % user.id, sku_id, count)
            if selected:
                #　写入集合数据  sku_id
                conn.sadd('cart_select_%s' % user.id, sku_id)
            # 返回结果
            return Response({'message': 'ok'})

        else:
            # 用户未登录 cookie
            # 生成响应对象
            response = Response({'message': 'ok'})
            # 获取cookie数据，判断以前是否写入过cookie
            cart_cookie = request.COOKIES.get('cart_cookie', None)
            if cart_cookie:
                # 有cookie 解密cookie
                cart = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 没有cookie数据赋值空字典，方便数据写入
                cart = {}

            #　判断存储的ｓｋｕ_id是否在ｃｏｏｋｉｅ中存储过
            cart_dict = cart.get(sku_id)
            if cart_dict:
                # 累加数量
                count += int(cart_dict['count'])
            # 数据更新写入
            cart[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 新数据重新加密
            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
            # 写入ｃｏｏｋｉｅ
            response.set_cookie('cart_cookie', cart_cookie, max_age=60*60*64*7)

            return response

    # 查询购物车数据
    def get(self, request):
        '''把redis和cookie中的数据转化为字典统一操作'''
        # 判断用户登录状态
        try:
            user = request.user
        except:
            user = None

        if user:
            # 用户已登录 redis
            # 建立redis连接
            conn = get_redis_connection('cart')
            #　获取hash数据 sku_id count
            sku_count = conn.hgetall('cart_%s' % user.id)

            # 获取集合数据  sku_id
            cart_selected = conn.smembers('cart_select_%s' % user.id)
            # 将hash数据和集合数据转为字典数据
            cart = {}
            for sku_id, count in sku_count.items():
                cart[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }

        else:
            # 用户未登录 cookie
            # 生成响应对象
            response = Response({'message': 'ok'})
            # 获取cookie数据，判断以前是否写入过cookie
            cart_cookie = request.COOKIES.get('cart_cookie', None)
            if cart_cookie:
                # 有cookie 解密cookie
                cart = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 没有cookie数据赋值空字典，方便数据写入
                cart = {}

        # 数据对象查询
        skus = SKU.objects.filter(id__in=cart.keys())
        # 添加返回属性
        for sku in skus:
            sku.count = cart[sku.id]['count']
            sku.selected = cart[sku.id]['selected']

        ser = CartsSerializers(skus, many=True)

        return Response(ser.data)

    # 修改购物车数据
    def put(self, request):
        # 1获取前端数据
        data = request.data
        # 2验证数据
        ser = CartSerializers(data=data)
        ser.is_valid()
        # 3获取验证后的数据
        sku_id = ser.validated_data['sku_id']
        count = ser.validated_data['count']
        selected = ser.validated_data['selected']

        # 判断用户登录状态
        try:
            user = request.user
        except:
            user = None

        if user:
            # 用户已登录 redis
            # 建立redis连接
            conn = get_redis_connection('cart')
            #　更新hash数据 sku_id count
            conn.hset('cart_%s' % user.id, sku_id, count)
            if selected:
                # 更新集合数据  sku_id
                conn.sadd('cart_select_%s' % user.id, sku_id)
            else:
                # 删除
                conn.srem('cart_select_%s' % user.id, sku_id)
            # 返回结果
            return Response(ser.data)

        else:
            # 用户未登录 cookie
            # 生成响应对象
            response = Response(ser.data)
            # 获取cookie数据，判断以前是否写入过cookie
            cart_cookie = request.COOKIES.get('cart_cookie', None)
            if cart_cookie:
                # 有cookie 解密cookie
                cart = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 没有cookie数据赋值空字典，方便数据写入
                cart = {}
            # 数据更新写入
            cart[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 新数据重新加密
            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
            # 写入ｃｏｏｋｉｅ
            response.set_cookie('cart_cookie', cart_cookie, max_age=60*60*64*7)

            return response

    # 删除购物车数据
    def delete(self, request):
        # 1获取前端数据
        data = request.data
        # 2验证数据
        ser = CartDeleteSerializers(data=data)
        ser.is_valid()
        # 3获取验证后的数据
        sku_id = ser.validated_data['sku_id']

        # 判断用户登录状态
        try:
            user = request.user
        except:
            user = None

        if user:
            # 用户已登录 redis
            # 建立redis连接
            conn = get_redis_connection('cart')
            # 删除hash数据 sku_id count
            conn.hdel('cart_%s' % user.id, sku_id)
            #　删除集合数据  sku_id
            conn.srem('cart_select_%s' % user.id, sku_id)
            # 返回结果
            return Response({'message': 'ok'})

        else:
            # 用户未登录 cookie
            # 生成响应对象
            response = Response({'message': 'ok'})
            # 获取cookie数据，判断以前是否写入过cookie
            cart_cookie = request.COOKIES.get('cart_cookie', None)
            if cart_cookie:
                # 有cookie 解密cookie
                cart = pickle.loads(base64.b64decode(cart_cookie))
                if sku_id in cart:
                    # 删除数据
                    del cart[sku_id]
                # 新数据重新加密
                cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
                # 写入ｃｏｏｋｉｅ
                response.set_cookie('cart_cookie', cart_cookie, max_age=60*60*64*7)

            return response


class CartSelectionView(APIView):
    '''购物车全选逻辑实现'''

    def perform_authentication(self, request):
        # 进入视图函数后调用试图方法先不进行用户验证
        pass

    def put(self, request):
        # 1获取前端数据
        data = request.data
        # 2验证数据
        ser = CartSelectionSerializers(data=data)
        ser.is_valid()
        # 3获取验证后的数据
        selected = ser.validated_data['selected']

        # 判断用户登录状态
        try:
            user = request.user
        except:
            user = None

        if user:
            # 用户已登录 redis
            # 建立redis连接
            conn = get_redis_connection('cart')
            # 从hash中获取所有的sku_id
            sku_count = conn.hgetall('cart_%s' % user.id)
            sku_ids = sku_count.keys()
            # 判断全选状态
            if selected:
                # 更新集合数据  sku_id
                conn.sadd('cart_select_%s' % user.id, *sku_ids)
            else:
                # 删除
                conn.srem('cart_select_%s' % user.id, *sku_ids)
            # 返回结果
            return Response(ser.data)

        else:
            # 用户未登录 cookie
            # 生成响应对象
            response = Response(ser.data)
            # 获取cookie数据，判断以前是否写入过cookie
            cart_cookie = request.COOKIES.get('cart_cookie', None)
            if cart_cookie:
                # 有cookie 解密cookie
                cart = pickle.loads(base64.b64decode(cart_cookie))

                for sku_id in cart.keys():
                    cart[sku_id]['selected'] = selected

                # 新数据重新加密
                cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
                # 写入ｃｏｏｋｉｅ
                response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 64 * 7)

            return response